package com.heima.search.service.impl;

import com.heima.article.client.ArticleFeign;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.exception.LeadException;
import com.heima.common.threadlocal.UserThreadLocalUtils;
import com.heima.common.util.JsonUtils;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.search.dtos.UserSearchDto;
import com.heima.search.service.ApArticleSearchService;
import com.heima.search.service.IApUserSearchService;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ApArticleSearchServiceImpl implements ApArticleSearchService {

    @Autowired
    private RestHighLevelClient client;

    @Autowired
    private ArticleFeign articleFeign;

    @Override
    public void loadArticleToEs(ArticleDto dto) {
        //组装数据
        Map<String,Object> map = new HashMap<>();
        map.put("id",dto.getId());
        map.put("title",dto.getTitle());
        map.put("publishTime",dto.getPublishTime());
        map.put("authorId",dto.getAuthorId());
        map.put("images",dto.getImages());
        map.put("layout",dto.getLayout());
        //将map转为json格式数据
        String articleJson = JsonUtils.toString(map);

        //完成数据导入
        IndexRequest indexRequest = new IndexRequest("app_info_article");
        //指定导入的数据
        indexRequest.source(articleJson, XContentType.JSON).id(dto.getId().toString());
        try {
            client.index(indexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Autowired
    private IApUserSearchService apUserSearchService;

    @Override
    public List<ArticleDto> searchArticle(UserSearchDto dto) {
        //获取用户id
        Integer userId = UserThreadLocalUtils.getUserId();
        apUserSearchService.saveSearchWords(userId,dto);
        //构建查询对象
        SearchRequest searchRequest = new SearchRequest("app_info_article");
        //封装查询条件
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //通过组合查询构建多个查询条件
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        //基于title进行关键字匹配查询
        boolQueryBuilder.must(QueryBuilders.matchQuery("title",dto.getSearchWords()).operator(Operator.AND));
        //如果页面传递了当前时间，需要查询发布时间小于当前时间的文章
        if(dto.getMinBehotTime()!=null){
            RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime").lte(dto.getMinBehotTime());
            boolQueryBuilder.filter(rangeQueryBuilder);
        }
        //将设置的方式方式关联到查询资源构建器
        sourceBuilder.query(boolQueryBuilder);
        //设置分页条件
        sourceBuilder.from(dto.getFromIndex());
        sourceBuilder.size(dto.getPageSize());
        //设置排序条件
        sourceBuilder.sort("publishTime", SortOrder.DESC);
        //关联封装的查询条件到请求对象中
        searchRequest.source(sourceBuilder);
        //执行查询
        try {
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
            //解析查询结果
            SearchHit[] searchHits = response.getHits().getHits();
            List<ArticleDto> list = new ArrayList<>();
            for (SearchHit searchHit : searchHits) {
                //获取数据
                String sourceAsString = searchHit.getSourceAsString();
                //解析json格式字符串
                ArticleDto articleDto = JsonUtils.toBean(sourceAsString, ArticleDto.class);
                list.add(articleDto);
            }
            return list;
        } catch (IOException e) {
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR,"查询文章数据失败");
        }

    }

    @Override
    public void ImportOneArticle2Es(Long articleId) {
        ArticleDto articleDto = articleFeign.findArticleById(articleId);
        //完成文章导入
        loadArticleToEs(articleDto);
    }

    @Override
    public void ArticleUpDown(Integer articleId, Integer enable) {
        //如果是上架操作，同步文章数据到索引库
        if(enable==1){
            ImportOneArticle2Es(Long.parseLong(articleId.toString()));
        }else{
            //如果是下架操作，同步删除索引库数据
            deleteArticeFromES(articleId);
        }
    }

    /**
     * 下架时，删除索引库数据
     */
    private void deleteArticeFromES(Integer articleId){
        DeleteRequest deleteRequest = new DeleteRequest("app_info_article",articleId.toString());
        try {
            client.delete(deleteRequest,RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
            throw new LeadException(AppHttpCodeEnum.SERVER_ERROR,"删除索引库数据失败");
        }
    }
}
